from django.shortcuts import render
from django.db import transaction
from django.conf import settings
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.permissions import IsAuthenticated
import os
import logging
from decimal import Decimal


from .models import Appointment, OrderManager
from .serializers import AppointmentCreateSerializer, AppointmentSerializer, OrderSerializer
from .utils import get_doctor_info, get_time_slot_info, generate_snowflake_id
from ..background.models import TimeSlot, Schedule
from ..user.models import Patient

logger = logging.getLogger(__name__)


class AppointmentAPIView(APIView):
    """预约API接口"""
    
    def post(self, request):
        """创建预约"""
        serializer = AppointmentCreateSerializer(data=request.data)
        if serializer.is_valid():
            # 从后端获取数据，确保安全
            patient_id = serializer.validated_data['patient_id']
            doctor_id = serializer.validated_data['doctor_id']
            time_slot_id = serializer.validated_data['time_slot_id']
            
            # 获取详细信息
            doctor_info = get_doctor_info(doctor_id)
            time_slot_info = get_time_slot_info(time_slot_id)
            
            if not doctor_info or not time_slot_info:
                return Response({'message': '获取信息失败'}, status=status.HTTP_400_BAD_REQUEST)
            
            try:
                with transaction.atomic():
                    # 获取时间段对象
                    time_slot = TimeSlot.objects.get(id=time_slot_id)
                    
                    # 检查是否还有可用号源
                    if time_slot.total_numbers <= 0:
                        return Response({'message': '该时间段已无可用号源'}, status=status.HTTP_400_BAD_REQUEST)
                    
                    # 获取费用并转换为Decimal
                    fee_str = time_slot_info['fee'].replace('¥', '').strip()
                    fee_decimal = Decimal(fee_str)
                    
                    # 获取就诊人信息并检查余额
                    try:
                        patient = Patient.objects.get(id=patient_id)
                    except Patient.DoesNotExist:
                        return Response({'message': '就诊人不存在'}, status=status.HTTP_400_BAD_REQUEST)
                    
                    # 检查余额是否足够
                    if patient.price < fee_decimal:
                        return Response({'message': f'余额不足，当前余额：¥{patient.price}，需要：¥{fee_decimal}'}, 
                                       status=status.HTTP_400_BAD_REQUEST)
                    
                    # 创建预约，使用雪花ID
                    appointment = Appointment(
                        patient_id=patient_id,
                        doctor_id=doctor_id,
                        doctor_name=doctor_info['name'],
                        doctor_title=doctor_info['title'],
                        hospital_name=doctor_info['hospital_name'],
                        hospital_address=doctor_info['hospital_address'],
                        department=doctor_info['department'],
                        appointment_date=time_slot_info['date'],
                        appointment_weekday=time_slot_info['weekday'],
                        time_slot=time_slot_info['time_slot'],
                        fee=time_slot_info['fee'],
                        status='confirmed'  # 直接设为已确认状态，因为已经扣款
                    )
                    appointment.save()  # save方法会调用自定义的雪花ID生成
                    
                    # 创建订单
                    amount = fee_str
                    order = OrderManager.create_order(
                        patient_id=patient_id,
                        doctor_id=doctor_id,
                        appointment_id=appointment.id,
                        amount=amount
                    )
                    
                    # 扣减就诊人余额
                    patient.price -= fee_decimal
                    patient.save()
                    logger.info(f"扣减就诊人余额成功 - 就诊人ID={patient_id}, 扣减金额={fee_decimal}, 当前余额={patient.price}")
                    
                    # 更新订单状态为已支付
                    OrderManager.update_order_status(
                        order_id=order['id'],
                        status='paid',
                        payment_method='balance'  # 使用余额支付
                    )
                    
                    # 更新时间段可用号源数量（预约成功后次数减少）
                    time_slot.total_numbers -= 1
                    time_slot.save()
                    
                    # 更新排班表可用号源数量
                    schedule = time_slot.schedule
                    schedule.total_numbers -= 1
                    schedule.save()
                    
                    # 返回预约和订单信息
                    return Response({
                        'message': '预约创建成功',
                        'appointment_id': appointment.id,
                        'order_id': order['id'],
                        'order_number': order['order_number'],
                        'amount': amount,
                        'status': 'confirmed',
                        'payment_method': 'balance',
                        'remaining_balance': str(patient.price)
                    })
            except Exception as e:
                logger.error(f"创建预约失败: {str(e)}")
                return Response({'message': f'创建预约失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class AppointmentDetailAPIView(APIView):
    """预约详情API接口"""
    
    def get(self, request, appointment_id):
        """获取预约详情"""
        try:
            appointment = Appointment.objects.get(id=appointment_id)
            serializer = AppointmentSerializer(appointment)
            return Response(serializer.data)
        except Appointment.DoesNotExist:
            return Response({'message': '预约不存在'}, status=status.HTTP_404_NOT_FOUND)
    
    def delete(self, request, appointment_id):
        """取消预约并物理删除"""
        try:
            appointment = Appointment.objects.get(id=appointment_id)
            
            # 只有待确认或已确认的预约可以取消
            if appointment.status not in ['pending', 'confirmed']:
                return Response({'message': '只有待确认或已确认的预约可以取消'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 获取订单信息
            orders = OrderManager.get_orders_by_appointment(appointment_id)
            
            with transaction.atomic():
                # 如果是已确认状态（已扣款），需要退还费用
                if appointment.status == 'confirmed' and orders:
                    try:
                        # 获取就诊人信息
                        patient = Patient.objects.get(id=appointment.patient_id)
                        
                        # 获取订单金额
                        order = orders[0]  # 假设一个预约只有一个订单
                        refund_amount = Decimal(str(order['amount']))
                        
                        # 退还费用
                        patient.price += refund_amount
                        patient.save()
                        
                        logger.info(f"退还就诊人余额成功 - 就诊人ID={patient.id}, 退款金额={refund_amount}, 当前余额={patient.price}")
                    except Patient.DoesNotExist:
                        logger.error(f"退款失败：找不到就诊人 ID={appointment.patient_id}")
                        return Response({'message': '找不到就诊人信息'}, status=status.HTTP_400_BAD_REQUEST)
                
                # 获取时间段信息以恢复预约次数
                try:
                    # 查找对应的TimeSlot
                    time_slots = TimeSlot.objects.filter(
                        schedule__doctor_id=appointment.doctor_id,
                        schedule__date=appointment.appointment_date
                    )
                    
                    logger.info(f"查询条件: doctor_id={appointment.doctor_id}, date={appointment.appointment_date}, time_slot字符串={appointment.time_slot}")
                    logger.info(f"查询结果: 找到了{time_slots.count()}个时间段")
                    
                    matched_slot = None
                    # 通过字符串比较找到对应的时间段
                    for ts in time_slots:
                        ts_str = f"{ts.start_time.strftime('%H:%M')}-{ts.end_time.strftime('%H:%M')}"
                        logger.info(f"比较: 时间段ID={ts.id}, 时间范围={ts_str}, appointment.time_slot={appointment.time_slot}")
                        if ts_str == appointment.time_slot:
                            matched_slot = ts
                            logger.info(f"找到匹配的时间段: ID={ts.id}")
                            break
                    
                    if matched_slot:
                        # 使用找到的匹配时间段
                        logger.info(f"使用匹配的时间段: ID={matched_slot.id}, 更新前total_numbers={matched_slot.total_numbers}")
                        matched_slot.total_numbers += 1
                        matched_slot.save()
                        
                        # 更新排班表
                        schedule = matched_slot.schedule
                        schedule.total_numbers += 1
                        schedule.save()
                        logger.info(f"更新成功: 时间段ID={matched_slot.id}, 更新后total_numbers={matched_slot.total_numbers}")
                    elif time_slots.exists():
                        # 如果没有精确匹配，使用第一个时间段
                        time_slot = time_slots.first()
                        logger.info(f"没有匹配的时间段，使用第一个: ID={time_slot.id}, 更新前total_numbers={time_slot.total_numbers}")
                        
                        # 增加时间段可用号源数（取消预约后次数增加）
                        time_slot.total_numbers += 1
                        time_slot.save()
                        
                        # 更新排班表
                        schedule = time_slot.schedule
                        schedule.total_numbers += 1
                        schedule.save()
                        logger.info(f"更新成功: 时间段ID={time_slot.id}, 更新后total_numbers={time_slot.total_numbers}")
                    else:
                        logger.warning(f"未找到对应的时间段: 医生ID={appointment.doctor_id}, 日期={appointment.appointment_date}")
                except Exception as e:
                    logger.error(f"恢复预约次数失败: {str(e)}")
                
                # 物理删除相关订单
                for order in orders:
                    OrderManager.delete_order(order['id'])
                
                # 物理删除预约
                appointment.delete()
            
            return Response({'message': '预约已删除'})
        except Appointment.DoesNotExist:
            return Response({'message': '预约不存在'}, status=status.HTTP_404_NOT_FOUND)


class PatientAppointmentAPIView(APIView):
    """患者预约API接口"""
    
    def get(self, request, patient_id):
        """获取患者的所有预约"""
        appointments = Appointment.objects.filter(patient_id=patient_id).order_by('-created_at')
        serializer = AppointmentSerializer(appointments, many=True)
        return Response(serializer.data)
    
    def delete(self, request, patient_id, appointment_id):
        """患者取消预约并物理删除"""
        try:
            appointment = Appointment.objects.get(id=appointment_id, patient_id=patient_id)
            
            # 只有待确认或已确认的预约可以取消
            if appointment.status not in ['pending', 'confirmed']:
                return Response({'message': '只有待确认或已确认的预约可以取消'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 获取订单信息
            orders = OrderManager.get_orders_by_appointment(appointment_id)
            
            with transaction.atomic():
                # 如果是已确认状态（已扣款），需要退还费用
                if appointment.status == 'confirmed' and orders:
                    try:
                        # 获取就诊人信息
                        patient = Patient.objects.get(id=appointment.patient_id)
                        
                        # 获取订单金额
                        order = orders[0]  # 假设一个预约只有一个订单
                        refund_amount = Decimal(str(order['amount']))
                        
                        # 退还费用
                        patient.price += refund_amount
                        patient.save()
                        
                        logger.info(f"退还就诊人余额成功 - 就诊人ID={patient.id}, 退款金额={refund_amount}, 当前余额={patient.price}")
                    except Patient.DoesNotExist:
                        logger.error(f"退款失败：找不到就诊人 ID={appointment.patient_id}")
                        return Response({'message': '找不到就诊人信息'}, status=status.HTTP_400_BAD_REQUEST)
                
                # 获取时间段信息以恢复预约次数
                try:
                    # 查找对应的TimeSlot
                    time_slots = TimeSlot.objects.filter(
                        schedule__doctor_id=appointment.doctor_id,
                        schedule__date=appointment.appointment_date
                    )
                    
                    logger.info(f"查询条件: doctor_id={appointment.doctor_id}, date={appointment.appointment_date}, time_slot字符串={appointment.time_slot}")
                    logger.info(f"查询结果: 找到了{time_slots.count()}个时间段")
                    
                    matched_slot = None
                    # 通过字符串比较找到对应的时间段
                    for ts in time_slots:
                        ts_str = f"{ts.start_time.strftime('%H:%M')}-{ts.end_time.strftime('%H:%M')}"
                        logger.info(f"比较: 时间段ID={ts.id}, 时间范围={ts_str}, appointment.time_slot={appointment.time_slot}")
                        if ts_str == appointment.time_slot:
                            matched_slot = ts
                            logger.info(f"找到匹配的时间段: ID={ts.id}")
                            break
                    
                    if matched_slot:
                        # 使用找到的匹配时间段
                        logger.info(f"使用匹配的时间段: ID={matched_slot.id}, 更新前total_numbers={matched_slot.total_numbers}")
                        matched_slot.total_numbers += 1
                        matched_slot.save()
                        
                        # 更新排班表
                        schedule = matched_slot.schedule
                        schedule.total_numbers += 1
                        schedule.save()
                        logger.info(f"更新成功: 时间段ID={matched_slot.id}, 更新后total_numbers={matched_slot.total_numbers}")
                    elif time_slots.exists():
                        # 如果没有精确匹配，使用第一个时间段
                        time_slot = time_slots.first()
                        logger.info(f"没有匹配的时间段，使用第一个: ID={time_slot.id}, 更新前total_numbers={time_slot.total_numbers}")
                        
                        # 增加时间段可用号源数（取消预约后次数增加）
                        time_slot.total_numbers += 1
                        time_slot.save()
                        
                        # 更新排班表
                        schedule = time_slot.schedule
                        schedule.total_numbers += 1
                        schedule.save()
                        logger.info(f"更新成功: 时间段ID={time_slot.id}, 更新后total_numbers={time_slot.total_numbers}")
                    else:
                        logger.warning(f"未找到对应的时间段: 医生ID={appointment.doctor_id}, 日期={appointment.appointment_date}")
                except Exception as e:
                    logger.error(f"恢复预约次数失败: {str(e)}")
                
                # 物理删除相关订单bu
                for order in orders:
                    OrderManager.delete_order(order['id'])
                
                # 物理删除预约
                appointment.delete()
            
            return Response({'message': '预约已删除'})
        except Appointment.DoesNotExist:
            return Response({'message': '预约不存在或不属于该患者'}, status=status.HTTP_404_NOT_FOUND)


class OrderAPIView(APIView):
    """订单API接口"""
    
    def get(self, request, order_id):
        """获取订单详情"""
        order = OrderManager.get_order(order_id)
        if not order:
            return Response({'message': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        
        return Response(order)
    
    def patch(self, request, order_id):
        """更新订单状态"""
        new_status = request.data.get('status')
        payment_method = request.data.get('payment_method')
        
        if not new_status:
            return Response({'message': '缺少status参数'}, status=status.HTTP_400_BAD_REQUEST)
        
        result = OrderManager.update_order_status(
            order_id=order_id,
            status=new_status,
            payment_method=payment_method
        )
        
        if result:
            # 获取更新后的订单
            order = OrderManager.get_order(order_id)
            return Response(order)
        else:
            return Response({'message': '订单不存在或更新失败'}, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
def doctor_appointment_stats(request, doctor_id):
    """医生预约统计API接口"""
    date_str = request.query_params.get('date')
    
    if not date_str:
        # 如果没有提供日期，默认使用今天
        date = timezone.now().date()
    else:
        try:
            # 尝试解析日期字符串，格式为YYYY-MM-DD
            date = timezone.datetime.strptime(date_str, '%Y-%m-%d').date()
        except ValueError:
            return Response({'message': '日期格式错误，请使用YYYY-MM-DD格式'}, status=status.HTTP_400_BAD_REQUEST)
    
    # 调用计算函数
    stats = calculate_doctor_daily_appointments(doctor_id, date)
    
    if stats is None:
        return Response({'message': '计算预约次数失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    # 构建响应数据
    response_data = {
        'doctor_id': doctor_id,
        'date': date.strftime('%Y-%m-%d'),
        'total_appointments': stats['total_appointments'],
        'available_appointments': stats['available_appointments'],
        'schedule_count': stats['schedule_count'],
        'time_slot_count': stats['time_slot_count']
    }
    
    return Response(response_data)


def calculate_doctor_daily_appointments(doctor_id, date):
    """计算医生当天排班的预约次数总和"""
    try:
        # 获取医生当天的所有排班
        schedules = Schedule.objects.filter(doctor_id=doctor_id, date=date)
        
        if not schedules.exists():
            return {
                'total_appointments': 0,
                'available_appointments': 0,
                'schedule_count': 0,
                'time_slot_count': 0
            }
        
        # 计算总预约数
        total_appointments = 0
        available_appointments = 0
        
        for schedule in schedules:
            # 获取排班下的所有时间段
            time_slots = TimeSlot.objects.filter(schedule=schedule)
            
            # 累加每个时间段的可用号源数
            for time_slot in time_slots:
                try:
                    # 使用total_numbers字段
                        total_appointments += time_slot.total_numbers
                except Exception as e:
                    logger.error(f"处理时间段ID={time_slot.id}时出错: {str(e)}")
            
            # 记录排班表中的总号源数
            try:
                if hasattr(schedule, 'total_numbers'):
                    available_appointments += schedule.total_numbers
                else:
                    logger.warning(f"排班ID={schedule.id}没有total_numbers字段")
            except Exception as e:
                logger.error(f"处理排班ID={schedule.id}时出错: {str(e)}")
        
        return {
            'total_appointments': total_appointments,
            'available_appointments': available_appointments,
            'schedule_count': schedules.count(),
            'time_slot_count': TimeSlot.objects.filter(schedule__in=schedules).count()
        }
    except Exception as e:
        logger.error(f"计算医生预约次数失败: {str(e)}")
        import traceback
        logger.error(traceback.format_exc())
        return None


